#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <openssl/sha.h>

typedef struct {
    int id;
    char username[50];
    char password[SHA256_DIGEST_LENGTH*2 + 1];
    int role; // 0: 普通用户, 1: 管理员
} User;

typedef struct {
    int seat_id;
    int status; 
    int user_id;
    char start_time[20];
    char end_time[20];
} Seat;

typedef struct {
    int seat_id;
    int user_id;
    char start_time[20];
    char end_time[20];
} Reservation;

User users[100];
int user_count = 0;
Seat seats[100];
int seat_count = 0;
Reservation reservations[1000];
int reservation_count = 0;

void register_user();
void register_admin();
int is_username_exists(char *username);
void encrypt_password(char *password, char *encrypted_password);
int is_valid_time(char *time_str);
int is_time_conflict(int seat_id, char *start_time, char *end_time);
void login();
void manage_users(int user_index);
void manage_seats(int user_index);
void view_my_reservations(int user_id);
// void auto_release_expired_seats();
void visualize_seats();
void statistics();
void save_data();
void load_data();
void initialize_seats();
void admin_release_seat(int user_index);

int main() {
    load_data();
    initialize_seats();
    int choice;
    time_t last_check = time(NULL);
    
    while (1) {
        // 每5分钟检查一次过期座位
        time_t now = time(NULL);
        if (difftime(now, last_check) >= 3) { // 300秒 = 5分钟
            // auto_release_expired_seats();
            last_check = now;
        }
        
        printf("\n=== 图书馆座位预约系统 ===\n");
        printf("1. 用户注册\n");
        printf("2. 管理员注册\n");
        printf("3. 登录\n");
        printf("4. 退出\n");
        printf("请选择: ");
        scanf("%d", &choice);
        
        switch (choice) {
            case 1:
                register_user();
                break;
            case 2:
                register_admin();
                break;
            case 3:
                login();
                break;
            case 4:
                save_data();
                exit(0);
            default:
                printf("无效选择\n");
        }
    }
    return 0;
}

void register_user() {
    if (user_count >= 100) {
        printf("用户数量已达上限\n");
        return;
    }
    
    User new_user;
    new_user.id = user_count + 1;
    printf("请输入用户名: ");
    scanf("%49s", new_user.username);
    
    // 检查用户名是否已存在
    if (is_username_exists(new_user.username)) {
        printf("用户名已存在，请选择其他用户名\n");
        return;
    }
    
    printf("请输入密码: ");
    scanf("%49s", new_user.password);
    
    // 密码加密
    char salt[10] = "salt123";
    char salted_password[100];
    strcpy(salted_password, new_user.password);
    strcat(salted_password, salt);
    
    unsigned char hash[SHA256_DIGEST_LENGTH];
    SHA256((unsigned char*)salted_password, strlen(salted_password), hash);
    
    // 将哈希值转换为十六进制字符串
    for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
        sprintf(&new_user.password[i*2], "%02x", hash[i]);
    }
    new_user.password[SHA256_DIGEST_LENGTH*2] = '\0';
    
    new_user.role = 0; 
    
    users[user_count++] = new_user;
    printf("注册成功！用户ID: %d\n", new_user.id);
}

void register_admin() {
    if (user_count >= 100) {
        printf("用户数量已达上限\n");
        return;
    }
    
    User new_admin;
    new_admin.id = user_count + 1;
    printf("请输入管理员用户名: ");
    scanf("%49s", new_admin.username);
    
    // 检查用户名是否已存在
    if (is_username_exists(new_admin.username)) {
        printf("用户名已存在，请选择其他用户名\n");
        return;
    }
    
    printf("请输入管理员密码: ");
    scanf("%49s", new_admin.password);
    
    // 密码加密
    char salt[10] = "salt123";
    char salted_password[100];
    strcpy(salted_password, new_admin.password);
    strcat(salted_password, salt);
    
    unsigned char hash[SHA256_DIGEST_LENGTH];
    SHA256((unsigned char*)salted_password, strlen(salted_password), hash);
    
    // 将哈希值转换为十六进制字符串
    for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
        sprintf(&new_admin.password[i*2], "%02x", hash[i]);
    }
    new_admin.password[SHA256_DIGEST_LENGTH*2] = '\0';
    
    new_admin.role = 1; // 管理员角色
    
    users[user_count++] = new_admin;
    printf("管理员注册成功！用户ID: %d\n", new_admin.id);
}

void login() {
    char username[50], password[50];
    printf("请输入用户名: ");
    scanf("%49s", username);
    printf("请输入密码: ");
    scanf("%49s", password);
    
    // 密码加密
    char salt[10] = "salt123";
    char salted_password[100];
    strcpy(salted_password, password);
    strcat(salted_password, salt);
    
    unsigned char hash[SHA256_DIGEST_LENGTH];
    SHA256((unsigned char*)salted_password, strlen(salted_password), hash);
    
    // 将哈希值转换为十六进制字符串
    char encrypted_password[SHA256_DIGEST_LENGTH*2 + 1];
    for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
        sprintf(&encrypted_password[i*2], "%02x", hash[i]);
    }
    encrypted_password[SHA256_DIGEST_LENGTH*2] = '\0';
    
    for (int i = 0; i < user_count; i++) {
        if (strcmp(users[i].username, username) == 0 && 
            strcmp(users[i].password, encrypted_password) == 0) {
            printf("登录成功！欢迎 %s\n", username);
            
            int choice;
            while (1) {
                printf("\n=== 用户菜单 ===\n");
                printf("1. 管理用户信息\n");
                printf("2. 管理座位\n");
                printf("3. 查看我的预约\n");
                printf("4. 座位状态可视化\n");
                printf("5. 数据统计\n");
                printf("6. 管理员座位释放\n");
                printf("7. 退出登录\n");
                printf("请选择: ");
                scanf("%d", &choice);
                
                switch (choice) {
                    case 1:
                        manage_users(i);
                        break;
                    case 2:
                        manage_seats(i);
                        break;
                    case 3:
                        view_my_reservations(i+1);
                        break;
                    case 4:
                        visualize_seats();
                        break;
                    case 5:
                        statistics();
                        break;
                    case 6:
                        if (users[i].role == 1) { // 检查是否为管理员
                            admin_release_seat(i);
                        } else {
                            printf("权限不足\n");
                        }
                        break;
                    case 7:
                        return;
                    default:
                        printf("无效选择\n");
                }
            }
        }
    }
    printf("用户名或密码错误\n");
}

void manage_users(int user_index) {
    int choice;
    while (1) {
        printf("\n=== 用户信息管理 ===\n");
        printf("1. 查看个人信息\n");
        printf("2. 修改密码\n");
        printf("3. 返回\n");
        printf("请选择: ");
        scanf("%d", &choice);
        
        switch (choice) {
            case 1:
                printf("用户ID: %d\n", users[user_index].id);
                printf("用户名: %s\n", users[user_index].username);
                printf("角色: %s\n", users[user_index].role ? "管理员" : "普通用户");
                break;
            case 2: {
                char new_password[50];
                printf("请输入新密码: ");
                scanf("%s", new_password);
                encrypt_password(new_password, users[user_index].password);
                printf("密码修改成功\n");
                save_data(); // 保存数据到文件
                break;
            }
            case 3:
                return;
            default:
                printf("无效选择\n");
        }
    }
}

void manage_seats(int user_index) {
    int choice;
    int seat_id;
    char date[11], start_time_str[6], end_time_str[6];
    char start_time[20], end_time[20];
    
    while (1) {
        printf("\n=== 座位管理 ===\n");
        printf("1. 预约座位\n");
        printf("2. 取消预约\n");
        printf("3. 查看所有座位\n");
        printf("4. 返回\n");
        printf("请选择: ");
        scanf("%d", &choice);
        
        switch (choice) {
            case 1: {
                printf("请输入座位ID: ");
                scanf("%d", &seat_id);
                printf("请输入日期 (YYYY-MM-DD): ");
                scanf("%10s", date);
                printf("请输入开始时间 (HH:MM): ");
                scanf("%5s", start_time_str);
                printf("请输入结束时间 (HH:MM): ");
                scanf("%5s", end_time_str);
                
                // 验证时间格式和范围
                if (!is_valid_time(start_time_str) || !is_valid_time(end_time_str)) {
                    printf("时间格式错误或不在允许范围内 (9:00-22:00)\n");
                    break;
                }
                
                // 构造完整时间字符串
                sprintf(start_time, "%s %s", date, start_time_str);
                sprintf(end_time, "%s %s", date, end_time_str);
                
                // 检查结束时间是否晚于开始时间
                if (strcmp(start_time, end_time) >= 0) {
                    printf("结束时间必须晚于开始时间\n");
                    break;
                }
                
                // 查找座位
                int seat_found = 0;
                for (int i = 0; i < seat_count; i++) {
                    if (seats[i].seat_id == seat_id) {
                        seat_found = 1;
                        break;
                    }
                }
                
                if (!seat_found) {
                    printf("座位不存在\n");
                    break;
                }
                
                // 检查时间冲突
                if (is_time_conflict(seat_id, start_time, end_time)) {
                    printf("该时间段已被预约\n");
                    break;
                }
                
                // 添加预约记录
                if (reservation_count >= 1000) {
                    printf("预约数量已达上限\n");
                    break;
                }
                
                reservations[reservation_count].seat_id = seat_id;
                reservations[reservation_count].user_id = user_index + 1;
                strcpy(reservations[reservation_count].start_time, start_time);
                strcpy(reservations[reservation_count].end_time, end_time);
                reservation_count++;
                
                // 记录预约日志
                FILE *log_file = fopen("reservation_log.txt", "a");
                if (log_file != NULL) {
                    fprintf(log_file, "用户ID: %d, 用户名: %s, 座位号: %d, 预约时间: %s 到 %s\n", 
                            user_index + 1, users[user_index].username, seat_id, start_time, end_time);
                    fclose(log_file);
                }
                
                printf("座位预约成功\n");
                save_data(); // 保存数据到文件
                break;
            }
            case 2: {
                int seat_id;
                char date[11], start_time_str[6];
                char start_time[20];
                
                printf("请输入要取消预约的座位ID: ");
                scanf("%d", &seat_id);
                printf("请输入日期 (YYYY-MM-DD): ");
                scanf("%10s", date);
                printf("请输入开始时间 (HH:MM): ");
                scanf("%5s", start_time_str);
                
                // 构造完整时间字符串
                sprintf(start_time, "%s %s", date, start_time_str);
                
                // 查找预约记录
                int found = 0;
                for (int i = 0; i < reservation_count; i++) {
                    if (reservations[i].seat_id == seat_id && 
                        reservations[i].user_id == user_index + 1 &&
                        strcmp(reservations[i].start_time, start_time) == 0) {
                        // 删除预约记录（将后面的记录前移）
                        for (int j = i; j < reservation_count - 1; j++) {
                            reservations[j] = reservations[j + 1];
                        }
                        reservation_count--;
                        printf("座位预约已取消\n");
                        save_data(); // 保存数据到文件
                        found = 1;
                        break;
                    }
                }
                if (!found) {
                    printf("未找到您预约的座位\n");
                }
                break;
            }
            case 3:
                visualize_seats();
                break;
            case 4:
                return;
            default:
                printf("无效选择\n");
        }
    }
}

void view_my_reservations(int user_id) {
    printf("\n=== 我的预约 ===\n");
    int found = 0;
    for (int i = 0; i < reservation_count; i++) {
        if (reservations[i].user_id == user_id) {
            printf("座位ID: %d, 开始时间: %s, 结束时间: %s\n", 
                   reservations[i].seat_id, reservations[i].start_time, reservations[i].end_time);
            found = 1;
        }
    }
    if (!found) {
        printf("您没有预约任何座位\n");
    }
}

void auto_release_expired_seats() {
    time_t now = time(NULL);
    struct tm *local_time = localtime(&now);
    char current_time[20];
    strftime(current_time, sizeof(current_time), "%Y-%m-%d %H:%M", local_time);
    
    for (int i = 0; i < reservation_count; i++) {
        // 比较当前时间与座位结束时间
        if (strcmp(current_time, reservations[i].end_time) >= 0) {
            // 记录日志
            FILE *log_file = fopen("release_log.txt", "a");
            if (log_file != NULL) {
                // fprintf(log_file, "用户ID: %d, 座位号: %d, 开始时间：%s,自动释放时间: %s\n", 
                //         reservations[i].user_id, reservations[i].seat_id, reservations[i].start_time,current_time);
                fprintf(log_file, "座位%d于%s自动释放\n", reservations[i].seat_id, current_time);
                fclose(log_file);
            }
            // 删除预约记录（将后面的记录前移）
            for (int j = i; j < reservation_count - 1; j++) {
                reservations[j] = reservations[j + 1];
            }
            reservation_count--;
            i--; // 调整索引，因为数组元素已经前移
        }
    }
    save_data(); // 保存数据到文件
}

void visualize_seats() {
    printf("\n=== 座位状态 ===\n");
    printf("座位ID\t用户ID\t开始时间\t\t\t结束时间\n");
    printf("----------------------------------------------------------------\n");
    for (int i = 0; i < reservation_count; i++) {
        printf("%d\t%d\t%s\t%s\n", 
               reservations[i].seat_id,
               reservations[i].user_id,
               reservations[i].start_time,
               reservations[i].end_time);
    }
    
    if (reservation_count == 0) {
        printf("暂无预约记录\n");
    }
}

void statistics() {
    printf("\n=== 数据统计 ===\n");
    
    // 统计座位使用率
    int total_seats = seat_count;
    int reserved_seats = 0;
    
    // 统计有预约记录的座位数量
    int seat_reserved[100] = {0}; // 假设最多100个座位
    for (int i = 0; i < reservation_count; i++) {
        if (!seat_reserved[reservations[i].seat_id]) {
            seat_reserved[reservations[i].seat_id] = 1;
            reserved_seats++;
        }
    }
    
    if (total_seats > 0) {
        float usage_rate = (float)reserved_seats / total_seats * 100;
        printf("座位使用率: %.2f%%\n", usage_rate);
    } else {
        printf("座位使用率: 0%%\n");
    }
    
    // 统计高频预约用户
    printf("\n高频预约用户:\n");
    for (int i = 0; i < user_count; i++) {
        int user_reservation_count = 0;
        for (int j = 0; j < reservation_count; j++) {
            if (reservations[j].user_id == users[i].id) {
                user_reservation_count++;
            }
        }
        if (user_reservation_count > 0) {
            printf("用户%s (ID: %d): 预约%d次\n", users[i].username, users[i].id, user_reservation_count);
        }
    }
}

void save_data() {
    int count = 0;
    // 保存用户数据
    FILE *user_file = fopen("users.txt", "w");
    if (user_file != NULL) {
        for (int i = 0; i < user_count; i++) {
            fprintf(user_file, "%d %s %s %d\n", users[i].id, users[i].username, users[i].password, users[i].role);
        }
        fclose(user_file);
    }
    
    // 保存座位数据
    FILE *seat_file = fopen("seats.txt", "w");
    if (seat_file != NULL) {
        for (int i = 0; i < seat_count; i++) {
            fprintf(seat_file, "%d %d %d %s %s\n", seats[i].seat_id, seats[i].status, seats[i].user_id, seats[i].start_time, seats[i].end_time);
        }
        fclose(seat_file);
    }
    
    // 保存预约数据
    FILE *reservation_file = fopen("reservations.txt", "w");
    if (reservation_file != NULL) {
        for (int i = 0; i < reservation_count; i++) {
            fprintf(reservation_file, "%d %d \"%s\" \"%s\"\n", reservations[i].seat_id, reservations[i].user_id, reservations[i].start_time, reservations[i].end_time);
        }
        fclose(reservation_file);
    }
}

void load_data() {
    // 从文件加载用户数据
    FILE *user_file = fopen("users.txt", "r");
    if (user_file != NULL) {
        user_count = 0;
        while (fscanf(user_file, "%d %s %s %d", &users[user_count].id, users[user_count].username, users[user_count].password, &users[user_count].role) == 4) {
            user_count++;
        }
        fclose(user_file);
    }
    
    // 从文件加载座位数据
    FILE *seat_file = fopen("seats.txt", "r");
    if (seat_file != NULL) {
        seat_count = 0;
        char line[256];
        while (fgets(line, sizeof(line), seat_file)) {
            // 解析座位数据行
            int result = sscanf(line, "%d %d %d %s %s", &seats[seat_count].seat_id, &seats[seat_count].status, &seats[seat_count].user_id, seats[seat_count].start_time, seats[seat_count].end_time);
            if (result >= 3) {  // 至少读取了前3个字段
                seat_count++;
            }
        }
        fclose(seat_file);
    }
    
    // 从文件加载预约数据
    FILE *reservation_file = fopen("reservations.txt", "r");
    if (reservation_file != NULL) {
        reservation_count = 0;
        char line[256];
        while (fgets(line, sizeof(line), reservation_file)) {
            // 解析预约数据行
            
            int result = sscanf(line,"%d %d \"%19[^\"]\" \"%19[^\"]\"", &reservations[reservation_count].seat_id, &reservations[reservation_count].user_id, reservations[reservation_count].start_time, reservations[reservation_count].end_time);
            if (result == 4) {  // 读取了所有4个字段
                reservation_count++;
            }
        }
        fclose(reservation_file);
    }

}

void admin_release_seat(int user_index) {
    int seat_id;
    printf("请输入要释放预约的座位ID: ");
    scanf("%d", &seat_id);
    
    // 查找座位
    int found = 0;
    for (int i = 0; i < reservation_count; i++) {
        if (reservations[i].seat_id == seat_id) { // 找到座位
            // 删除预约记录（将后面的记录前移）
            for (int j = i; j < reservation_count - 1; j++) {
                reservations[j] = reservations[j + 1];
            }
            // 记录释放日志
            FILE *log_file = fopen("release_log.txt", "a");
            if (log_file != NULL) {
                fprintf(log_file, "用户ID: %d, 用户名: %s, 座位号: %d, 释放时间: %s\n", 
                        reservations[i].user_id, users[user_index].username, seat_id, reservations[i].start_time);
                fclose(log_file);
            }
            
            reservation_count--;
            printf("座位%d的预约已成功释放\n", seat_id);
            save_data(); // 保存数据到文件
            found = 1;
            break;
        }
    }
    
    if (!found) {
        printf("座位不存在或未被预约\n");
    }
}

void initialize_seats() {
    // 如果座位文件不存在或座位数量为0，则初始化100个座位
    if (seat_count == 0) {
        for (int i = 0; i < 100; i++) {
            seats[i].seat_id = i + 1;
            seats[i].status = 0;  // 0表示空闲
            seats[i].user_id = 0;
            strcpy(seats[i].start_time, "");
            strcpy(seats[i].end_time, "");
        }
        seat_count = 100;
        printf("已初始化%d个座位\n", seat_count);
    } else {
        printf("已加载%d个座位\n", seat_count);
    }
}

int is_username_exists(char *username) {
    for (int i = 0; i < user_count; i++) {
        if (strcmp(users[i].username, username) == 0) {
            return 1; // 用户名已存在
        }
    }
    return 0; // 用户名不存在
}

void encrypt_password(char *password, char *encrypted_password) {
    // 密码加密
    char salt[10] = "salt123";
    char salted_password[100];
    strcpy(salted_password, password);
    strcat(salted_password, salt);
    
    unsigned char hash[SHA256_DIGEST_LENGTH];
    SHA256((unsigned char*)salted_password, strlen(salted_password), hash);
    
    // 将哈希值转换为十六进制字符串
    for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
        sprintf(&encrypted_password[i*2], "%02x", hash[i]);
    }
    encrypted_password[SHA256_DIGEST_LENGTH*2] = '\0';
}

int is_valid_time(char *time_str) {
    // 检查时间格式是否为 HH:MM，并且在9:00-22:00之间
    int hour, minute;
    if (sscanf(time_str, "%d:%d", &hour, &minute) != 2) {
        return 0; // 格式不正确
    }
    
    // 检查小时和分钟范围
    if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
        return 0; // 时间范围不正确
    }
    
    // 检查是否在9:00-22:00之间
    if (hour < 9 || hour >= 22) {
        return 0; // 不在允许的时间范围内
    }
    
    return 1; // 时间有效
}

int is_time_conflict(int seat_id, char *start_time, char *end_time) {
    // 检查新预约是否与现有预约时间冲突
    for (int i = 0; i < reservation_count; i++) {
        if (reservations[i].seat_id == seat_id) {
            // 检查时间是否重叠
            // 如果新预约的开始时间在现有预约的时间范围内，或者
            // 新预约的结束时间在现有预约的时间范围内，或者
            // 新预约完全包含现有预约
            if ((strcmp(start_time, reservations[i].start_time) >= 0 && strcmp(start_time, reservations[i].end_time) < 0) ||
                (strcmp(end_time, reservations[i].start_time) > 0 && strcmp(end_time, reservations[i].end_time) <= 0) ||
                (strcmp(start_time, reservations[i].start_time) <= 0 && strcmp(end_time, reservations[i].end_time) >= 0)) {
                return 1; // 时间冲突
            }
        }
    }
    return 0; // 无时间冲突
}